/*
 * Copyright 2018-present KunMinX
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.nsgf.library.data.repository;

import android.os.Build;

import com.alibaba.fastjson.JSONObject;
import com.google.gson.JsonObject;
import com.nsgf.library.data.api.APIs;
import com.nsgf.library.data.api.AccountService;
import com.nsgf.library.data.bean.ClockInBean;
import com.nsgf.library.data.bean.MessageBean;
import com.nsgf.library.data.bean.User;
import com.nsgf.library.data.bean.UserDataBean;
import com.nsgf.library.data.bean.UserInfo;
import com.nsgf.library.data.bean.WeatherBean;
import com.nsgf.library.data.bean.WorkOrderBean;
import com.nsgf.library.data.bean.WorkOrderDetailBean;
import com.nsgf.library.data.response.DataResult;
import com.nsgf.library.data.response.ResponseStatus;
import com.nsgf.library.data.response.ResultSource;
import com.nsgf.library.domain.request.AsyncTask;
import com.nsgf.skjz.domain.request.BaseHttpObserver;
import com.nsgf.skjz.domain.request.HttpOnNextListener;
import com.nsgf.library.utils.SysUtil;
import com.nsgf.skjz.utils.ToastUtils;

import java.io.File;
import java.io.IOException;
import java.util.List;
import java.util.concurrent.TimeUnit;

import io.reactivex.Observable;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.observers.DisposableObserver;
import io.reactivex.schedulers.Schedulers;
import okhttp3.Interceptor;
import okhttp3.MediaType;
import okhttp3.MultipartBody;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.logging.HttpLoggingInterceptor;
import retrofit2.Call;
import retrofit2.Response;
import retrofit2.Retrofit;
import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory;
import retrofit2.converter.gson.GsonConverterFactory;

/**
 * Create by GC at 24/10/29
 */
public class DataRepository {

    private static final DataRepository S_REQUEST_MANAGER = new DataRepository();

    // 获取到请求类型（MediaType）
    private static MediaType mediaType = MediaType.parse("application/json;charset=UTF-8");

    private DataRepository() {
    }

    public static DataRepository getInstance() {
        return S_REQUEST_MANAGER;
    }

    private static Retrofit retrofitCallAdapter;

    public static Retrofit getRetrofitInstance() {
        if (retrofitCallAdapter == null) {

            Interceptor headerInterceptor = a -> {
                Request originalRequest = a.request();
                Request.Builder requestBuilder = originalRequest.newBuilder()
                        .addHeader("Accept-Encoding", "gzip")
                        .addHeader("Accept", "application/json")
                        .addHeader("version", SysUtil.getAppVersion())
                        .addHeader("source", "android")
                        .addHeader("User-Agent", "android")
                        .addHeader("pda_model", Build.MODEL)
                        .addHeader(UserInfo.getInstance().getTokenName(), UserInfo.getInstance().getTokenValue())
                        .addHeader("sys_version", Build.VERSION.RELEASE)
                        .addHeader("Content-Type", "application/json; charset=utf-8")
                        .method(originalRequest.method(), originalRequest.body());
                Request request = requestBuilder.build();
                return a.proceed(request);
            };
            HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
            logging.setLevel(HttpLoggingInterceptor.Level.BODY);
            OkHttpClient client = new OkHttpClient.Builder()
                    .connectTimeout(30, TimeUnit.SECONDS)
                    .readTimeout(30, TimeUnit.SECONDS)
                    .writeTimeout(30, TimeUnit.SECONDS)
                    .addInterceptor(logging)
                    .addInterceptor(headerInterceptor)
                    .build();

            retrofitCallAdapter = new Retrofit.Builder()
                    .baseUrl(APIs.BASE_URL)
                    .client(client)
                    .addConverterFactory(MyGsonConverterFactory.create())
                    .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                    .build();
        }
        return retrofitCallAdapter;
    }


    public <T> void subscribe(Observable<T> o, DisposableObserver<T> s) {
        o.subscribeOn(Schedulers.io())
                .unsubscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
//                .retry(RETRY_COUNT)
                .subscribe(s);
    }


    private final Retrofit retrofit;

    {
        Interceptor headerInterceptor = a -> {
            Request originalRequest = a.request();
            Request.Builder requestBuilder = originalRequest.newBuilder()
                    .addHeader("Accept-Encoding", "gzip")
                    .addHeader("Accept", "application/json")
//                .addHeader("version", SysUtil.getAppVersion())
                    .addHeader("source", "android")
                    .addHeader("User-Agent", "android")
                    .addHeader("pda_model", Build.MODEL)
                    .addHeader(UserInfo.getInstance().getTokenName(), UserInfo.getInstance().getTokenValue())
                    .addHeader("sys_version", Build.VERSION.RELEASE)
                    .addHeader("Content-Type", "application/json; charset=utf-8")
                    .method(originalRequest.method(), originalRequest.body());
            Request request = requestBuilder.build();
            return a.proceed(request);
        };
        HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
        logging.setLevel(HttpLoggingInterceptor.Level.BODY);
        OkHttpClient client = new OkHttpClient.Builder()
                .connectTimeout(30, TimeUnit.SECONDS)
                .readTimeout(30, TimeUnit.SECONDS)
                .writeTimeout(30, TimeUnit.SECONDS)
                .addInterceptor(logging)
                .addInterceptor(headerInterceptor)
                .build();


        retrofit = new Retrofit.Builder()
                .baseUrl(APIs.BASE_URL)
                .client(client)
                .addConverterFactory(GsonConverterFactory.create())
                .build();
    }

    /**
     * TODO
     *
     * @param user ui 层填写的用户信息
     */
//    public Observable<DataResult<UserDataBean>> login(User user) {
//
//        // 使用 retrofit 或任意你喜欢的库实现网络请求。此处以 retrofit 写个简单例子，
//        // 并且如使用 rxjava，还可额外依赖 RxJavaCallAdapterFactory ，
//
//        return AsyncTask.doIO(emitter -> {
//
//            JsonObject jsonObject = new JsonObject();
//            jsonObject.addProperty("username", user.getName());
//            jsonObject.addProperty("password", user.getPassword());
//            RequestBody requestBody = RequestBody.create(mediaType, jsonObject.toString());
//
//            Call<UserDataBean> call = retrofit.create(AccountService.class).login(requestBody);
//            Response<UserDataBean> response;
//            try {
//                response = call.execute();
//                ResponseStatus responseStatus = new ResponseStatus(
//                        response.code(), response.isSuccessful(), ResultSource.NETWORK);
//                if (response.code() == 200) {
//                    emitter.onNext(new DataResult<>(response.body(), responseStatus));
//                } else
//                    emitter.onError(new Throwable());
//            } catch (IOException e) {
//                emitter.onNext(new DataResult<>(null,
//                        new ResponseStatus(0, false, ResultSource.NETWORK)));
//            }
//        });
//    }
    public Observable<DataResult<ResponseStatus<UserInfo>>> getLoginInfo() {


        // 使用 retrofit 或任意你喜欢的库实现网络请求。此处以 retrofit 写个简单例子，
        // 并且如使用 rxjava，还可额外依赖 RxJavaCallAdapterFactory ，

        return AsyncTask.doIO(emitter -> {

            Call<ResponseStatus<UserInfo>> call = retrofit.create(AccountService.class).getLoginInfo();
            Response<ResponseStatus<UserInfo>> response;
            try {
                response = call.execute();
                ResponseStatus responseStatus = new ResponseStatus(
                        response.code(), response.isSuccessful(), ResultSource.NETWORK);
                if (response.code() == 200) {
                    emitter.onNext(new DataResult<>(response.body(), responseStatus));
                } else
                    emitter.onError(new Throwable());
            } catch (IOException e) {
                emitter.onNext(new DataResult<>(null,
                        new ResponseStatus(0, false, ResultSource.NETWORK)));
            }
        });
    }


    public Observable<DataResult<MessageBean>> getMessage(String type, String search, String projectCode) {

        // 使用 retrofit 或任意你喜欢的库实现网络请求。此处以 retrofit 写个简单例子，
        // 并且如使用 rxjava，还可额外依赖 RxJavaCallAdapterFactory ，

        return AsyncTask.doIO(emitter -> {

            Call<MessageBean> call = retrofit.create(AccountService.class).getMessage(type, search, projectCode);
            Response<MessageBean> response;
            try {
                response = call.execute();
                ResponseStatus responseStatus = new ResponseStatus(
                        response.code(), response.isSuccessful(), ResultSource.NETWORK);
                if (response.code() == 200) {
                    emitter.onNext(new DataResult<>(response.body(), responseStatus));
                } else
                    emitter.onError(new Throwable());
            } catch (IOException e) {
                emitter.onNext(new DataResult<>(null,
                        new ResponseStatus(0, false, ResultSource.NETWORK)));
            }
        });
    }

    public Observable<DataResult<ResponseStatus<MessageBean.DataBean>>> getMessageDetail(String id, boolean warning) {
        return AsyncTask.doIO(emitter -> {
            Call<ResponseStatus<MessageBean.DataBean>> call;
            if (warning) {
                call = retrofit.create(AccountService.class).getWarningDetail(id);
            } else {
                call = retrofit.create(AccountService.class).getMessageDetail(id);
            }
            Response<ResponseStatus<MessageBean.DataBean>> response;
            try {
                response = call.execute();

                if (response.code() == 200) {
                    ResponseStatus responseStatus = new ResponseStatus(response.code(), response.isSuccessful(), ResultSource.NETWORK);
                    emitter.onNext(new DataResult<>(response.body(), responseStatus));
                } else
                    emitter.onError(new Throwable());
            } catch (IOException e) {
                emitter.onNext(new DataResult<>(null,
                        new ResponseStatus(0, false, ResultSource.NETWORK)));
            }
        });
    }

    public Observable<DataResult<ResponseStatus<MessageBean.DataBean>>> getUnreadCount(String projectCode, boolean type) {
        return AsyncTask.doIO(emitter -> {
            Call<ResponseStatus<MessageBean.DataBean>> call;
            if (type) {
                call = retrofit.create(AccountService.class).unreadWarningCount(projectCode);
            } else {
                call = retrofit.create(AccountService.class).unreadCount(projectCode);
            }
            Response<ResponseStatus<MessageBean.DataBean>> response;
            try {
                response = call.execute();

                ResponseStatus responseStatus = new ResponseStatus(response.code(), response.isSuccessful(), ResultSource.NETWORK);
                emitter.onNext(new DataResult<>(response.body(), responseStatus));
            } catch (IOException e) {
                emitter.onNext(new DataResult<>(null,
                        new ResponseStatus(0, false, e)));
            }
        });
    }

    public Observable<DataResult<ResponseStatus<String>>> setClearMessage(String type, String projectCode) {
        return AsyncTask.doIO(emitter -> {

            Call<ResponseStatus<String>> call = retrofit.create(AccountService.class).setClearMessage(type, projectCode);
            Response<ResponseStatus<String>> response;
            try {
                response = call.execute();
                ResponseStatus responseStatus = new ResponseStatus(response.code(), response.isSuccessful(), ResultSource.NETWORK);
                emitter.onNext(new DataResult<>(response.body(), responseStatus));
            } catch (IOException e) {
                emitter.onNext(new DataResult<>(null,
                        new ResponseStatus(0, false, e)));
            }
        });
    }

    public Observable<DataResult<ResponseStatus<String>>> setClearWarningMessage(String type, String projectCode) {
        return AsyncTask.doIO(emitter -> {

            Call<ResponseStatus<String>> call = retrofit.create(AccountService.class).setClearWarningMessage(type, projectCode);
            Response<ResponseStatus<String>> response;
            try {
                response = call.execute();

                if (response.code() == 200) {
                    ResponseStatus responseStatus = new ResponseStatus(response.code(), response.isSuccessful(), ResultSource.NETWORK);
                    emitter.onNext(new DataResult<>(response.body(), responseStatus));
                } else
                    emitter.onError(new Throwable());
            } catch (IOException e) {
                emitter.onNext(new DataResult<>(null,
                        new ResponseStatus(0, false, ResultSource.NETWORK)));
            }
        });
    }


    public Observable<DataResult<ClockInBean>> sameDayClockInDetail(String projectCode) {

        // 使用 retrofit 或任意你喜欢的库实现网络请求。此处以 retrofit 写个简单例子，
        // 并且如使用 rxjava，还可额外依赖 RxJavaCallAdapterFactory ，

        return AsyncTask.doIO(emitter -> {

            Call<ClockInBean> call = retrofit.create(AccountService.class).sameDayClockInDetail(projectCode);
            Response<ClockInBean> response;
            try {
                response = call.execute();
                ResponseStatus responseStatus = new ResponseStatus(
                        response.code(), response.isSuccessful(), ResultSource.NETWORK);
                emitter.onNext(new DataResult<>(response.body(), responseStatus));
            } catch (IOException e) {
                emitter.onNext(new DataResult<>(null,
                        new ResponseStatus(0, false, e)));
            }
        });
    }

    public Observable<DataResult<ResponseStatus<String>>> punchTheClock(String projectCode) {

        return AsyncTask.doIO(emitter -> {

            Call<ResponseStatus<String>> call = retrofit.create(AccountService.class).punchTheClock(projectCode);
            Response<ResponseStatus<String>> response;
            try {
                response = call.execute();
                ResponseStatus responseStatus = new ResponseStatus(
                        response.code(), response.isSuccessful(), ResultSource.NETWORK);
                emitter.onNext(new DataResult<>(response.body(), responseStatus));
            } catch (IOException e) {
                emitter.onNext(new DataResult<>(null,
                        new ResponseStatus(0, false, e)));
            }
        });
    }

    public Observable<DataResult<ClockInBean>> punchSummary(String projectCode, String yearMonth) {

        // 使用 retrofit 或任意你喜欢的库实现网络请求。此处以 retrofit 写个简单例子，
        // 并且如使用 rxjava，还可额外依赖 RxJavaCallAdapterFactory ，

        return AsyncTask.doIO(emitter -> {

            Call<ClockInBean> call = retrofit.create(AccountService.class).punchSummary(projectCode, yearMonth);
            Response<ClockInBean> response;
            try {
                response = call.execute();
                ResponseStatus responseStatus = new ResponseStatus(
                        response.code(), response.isSuccessful(), ResultSource.NETWORK);
                if (response.code() == 200) {
                    emitter.onNext(new DataResult<>(response.body(), responseStatus));
                } else
                    emitter.onError(new Throwable());
            } catch (IOException e) {
                emitter.onNext(new DataResult<>(null,
                        new ResponseStatus(0, false, ResultSource.NETWORK)));
            }
        });
    }


    public Observable<DataResult<ResponseStatus<Object>>> videoInfo(String deviceCode, String channelId, String callingMode) {

        // 使用 retrofit 或任意你喜欢的库实现网络请求。此处以 retrofit 写个简单例子，
        // 并且如使用 rxjava，还可额外依赖 RxJavaCallAdapterFactory ，

        return AsyncTask.doIO(emitter -> {

            Call<ResponseStatus<Object>> call = retrofit.create(AccountService.class).videoInfo(deviceCode, channelId, callingMode);
            Response<ResponseStatus<Object>> response;
            try {
                response = call.execute();
                ResponseStatus responseStatus = new ResponseStatus(
                        response.code(), response.isSuccessful(), ResultSource.NETWORK);
                if (response.code() == 200) {
                    emitter.onNext(new DataResult<>(response.body(), responseStatus));
                } else
                    emitter.onError(new Throwable());
            } catch (IOException e) {
                emitter.onNext(new DataResult<>(null,
                        new ResponseStatus(0, false, ResultSource.NETWORK)));
            }
        });
    }

    /**
     * 首页获取大坝巡查和经常检测
     *
     * @param patrolType
     * @return
     */
    public Observable<DataResult<ResponseStatus<List<WorkOrderBean>>>> sameDayPatrolTask(String patrolType) {
        return AsyncTask.doIO(emitter -> {

            Call<ResponseStatus<List<WorkOrderBean>>> call = retrofit.create(AccountService.class)
                    .sameDayPatrolTask(patrolType);
            Response<ResponseStatus<List<WorkOrderBean>>> response;
            try {
                response = call.execute();
                ResponseStatus responseStatus = new ResponseStatus(response.code(), response.isSuccessful(), ResultSource.NETWORK);
                emitter.onNext(new DataResult<>(response.body(), responseStatus));
            } catch (IOException e) {
                emitter.onNext(new DataResult<>(null,
                        new ResponseStatus(0, false, e)));
            }
        });
    }


    /**
     *
     * @param orderCode
     * @return
     */
    public Observable<DataResult<WorkOrderDetailBean>> patrolDetail(String orderCode) {
        return AsyncTask.doIO(emitter -> {

            Call<WorkOrderDetailBean> call = retrofit.create(AccountService.class)
                    .patrolDetail(orderCode);
            Response<WorkOrderDetailBean> response;
            try {
                response = call.execute();
                ResponseStatus responseStatus = new ResponseStatus(response.code(), response.isSuccessful(), ResultSource.NETWORK);
                emitter.onNext(new DataResult<>(response.body(), responseStatus));
            } catch (IOException e) {
                emitter.onNext(new DataResult<>(null,
                        new ResponseStatus(0, false, e)));
            }
        });
    }


    /**
     *
     * @param path
     * @return
     */
    public Observable<DataResult<ResponseStatus<WorkOrderDetailBean.FileDto>>> uploadFile(String path) {

        return AsyncTask.doIO(emitter -> {

            File file = new File(path);
            RequestBody requestBody = RequestBody.create(file, MediaType.parse("multipart/form-data"));
            MultipartBody.Part filePart = MultipartBody.Part.createFormData("file", file.getName(), requestBody);
            Call<ResponseStatus<WorkOrderDetailBean.FileDto>> call = retrofit.create(AccountService.class)
                    .uploadFile(filePart);
            Response<ResponseStatus<WorkOrderDetailBean.FileDto>> response;
            try {
                response = call.execute();

                ResponseStatus responseStatus = new ResponseStatus(response.code(), response.isSuccessful(), ResultSource.NETWORK);
                emitter.onNext(new DataResult<>(response.body(), responseStatus));
            } catch (IOException e) {
                emitter.onNext(new DataResult<>(null,
                        new ResponseStatus(0, false, e)));
            }
        });
    }

    /**
     * 新文件上传接口（使用 Observable）
     *
     * @param path 文件本地路径
     * @return
     */
    public Observable<DataResult<ResponseStatus<WorkOrderDetailBean.FileDto>>> newUploadFile(String path) {
        return AsyncTask.doIO(emitter -> {
            File file = new File(path);
            RequestBody requestBody = RequestBody.create(file, MediaType.parse("multipart/form-data"));
            MultipartBody.Part filePart = MultipartBody.Part.createFormData("file", file.getName(), requestBody);

            try {
                Observable<ResponseStatus<WorkOrderDetailBean.FileDto>> observable =
                        getRetrofitInstance().create(AccountService.class).newUploadFile(filePart);

                ResponseStatus<WorkOrderDetailBean.FileDto> response = observable.blockingFirst();
                ResponseStatus responseStatus = new ResponseStatus(200, true, ResultSource.NETWORK);
                emitter.onNext(new DataResult<>(response, responseStatus));
            } catch (Exception e) {
                emitter.onNext(new DataResult<>(null,
                        new ResponseStatus(0, false, e)));
            }
        });
    }


    /**
     *
     * @param jsonObject
     * @return
     */
    public Observable<DataResult<ResponseStatus<String>>> handleWorkOrder(JSONObject jsonObject) {
        return AsyncTask.doIO(emitter -> {
            RequestBody requestBody = RequestBody.create(mediaType, jsonObject.toString());
            Call<ResponseStatus<String>> call = retrofit.create(AccountService.class).handleWorkOrder(requestBody);
            Response<ResponseStatus<String>> response;
            try {
                response = call.execute();
                ResponseStatus responseStatus = new ResponseStatus(response.code(), response.isSuccessful(), ResultSource.NETWORK, response.message());
                emitter.onNext(new DataResult<>(response.body(), responseStatus));
            } catch (IOException e) {
                emitter.onNext(new DataResult<>(null,
                        new ResponseStatus(0, false, e)));
            }
        });
    }

    /**
     *
     * @param jsonObject
     * @return
     */

    public Observable<DataResult<ResponseStatus<String>>> reviewWorkOrder(JsonObject jsonObject) {
        return AsyncTask.doIO(emitter -> {
            RequestBody requestBody = RequestBody.create(mediaType, jsonObject.toString());
            Call<ResponseStatus<String>> call = retrofit.create(AccountService.class).reviewWorkOrder(requestBody);
            Response<ResponseStatus<String>> response;
            try {
                response = call.execute();

                if (response.code() == 200) {
                    ResponseStatus responseStatus = new ResponseStatus(response.code(), response.isSuccessful(), ResultSource.NETWORK);
                    emitter.onNext(new DataResult<>(response.body(), responseStatus));
                } else
                    emitter.onError(new Throwable());
            } catch (IOException e) {
                emitter.onNext(new DataResult<>(null,
                        new ResponseStatus(0, false, ResultSource.NETWORK)));
            }
        });
    }


    /**
     *
     * @param dictCode
     * @return
     */
    public Observable<DataResult<WeatherBean>> getDictItems(String dictCode) {
        return AsyncTask.doIO(emitter -> {

            Call<WeatherBean> call = retrofit.create(AccountService.class)
                    .getDictItems(dictCode);
            Response<WeatherBean> response;
            try {
                response = call.execute();

                if (response.code() == 200) {
                    ResponseStatus responseStatus = new ResponseStatus(response.code(), response.isSuccessful(), ResultSource.NETWORK);
                    emitter.onNext(new DataResult<>(response.body(), responseStatus));
                } else
                    emitter.onError(new Throwable());
            } catch (IOException e) {
                emitter.onNext(new DataResult<>(null,
                        new ResponseStatus(0, false, ResultSource.NETWORK)));
            }
        });
    }


}
